// Copyright (c) 2019 Presto Labs Pte. Ltd.
// Author: xguo

#pragma once

#include <memory>
#include <string>
#include <vector>

#include "coin2/exchange/base/symbology/product.h"
#include "coin2/exchange/base/symbology/util.h"

namespace coin2::exchange::base::symbology {

template <typename CurrencyT, typename ProductT>
class SpotProduct : public CurrencyPairProduct<CurrencyT> {
 public:
  SpotProduct(
      const CurrencyT& base,
      const CurrencyT& quote,
      const std::string& order_native_symbol,
      const std::string& feed_native_symbol,
      const ExchangeType exchange)
      : CurrencyPairProduct<CurrencyT>(
            base,
            quote,
            ConvertToSpotNormStr(base, quote),
            order_native_symbol,
            ConvertToSpotNormStr(base, quote),
            feed_native_symbol,
            MarketType::Spot,
            exchange) {}

 public:
  static std::unique_ptr<ProductT> FromNormStrImpl(
      const std::string& product_str,
      const int64_t resolve_timestamp) {
    std::string base_str;
    std::string quote_str;
    bool success = ParseSpotNormStr(product_str, &base_str, &quote_str);
    if (success) {
      auto base = CurrencyT::FromNormStrNoThrow(base_str, resolve_timestamp);
      auto quote = CurrencyT::FromNormStrNoThrow(quote_str, resolve_timestamp);
      if (base && quote) {
        return std::make_unique<ProductT>(*base, *quote);
      } else {
        return {};
      }
    } else {
      return {};
    }
  }

  IProduct* Clone() const final {
    auto* prod = new ProductT(
        CurrencyPairProduct<CurrencyT>::base_impl(),
        CurrencyPairProduct<CurrencyT>::quote_impl());
    prod->resolve_timestamp_ = this->resolve_timestamp();
    return prod;
  }

 private:
  static bool
  ParseSpotNormStr(const std::string currency_pair, std::string* base, std::string* quote) {
    std::vector<std::string> out;
    std::string temp;
    out = Split(currency_pair, "-");
    if (out.size() == 2) {
      temp = out[0];
      out = Split(out[1], ".");
      if (out.size() == 2) {
        *quote = out[1];
      } else if (out.size() == 1) {
        *quote = out[0];
      } else {
        return false;
      }
      *base = temp;
      return true;
    }

    return false;
  }

  static std::string ConvertToSpotNormStr(const ICurrency& base, const ICurrency& quote) {
    std::stringstream ss;
    ss << base.currency() << "-" << quote.currency();
    return ss.str();
  }
};

}  // namespace coin2::exchange::base::symbology
